#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Worker客户端主程序
整合调度系统连接器和任务分发器，提供完整的Worker功能
"""

import time
import signal
import logging
import threading
from typing import Dict, Any, Optional
from datetime import datetime

try:
    # 尝试相对导入（当作为模块使用时）
    from .scheduler_connector import SchedulerConnector, RemoteTask
    from .task_dispatcher import TaskDispatcher
    from .config_manager import get_config
    from .oss_uploader import OSSUploader
except ImportError:
    # 直接导入（当直接运行时）
    from scheduler_connector import SchedulerConnector, RemoteTask
    from task_dispatcher import TaskDispatcher
    from config_manager import get_config
    from oss_uploader import OSSUploader


class WorkerClient:
    """Worker客户端"""

    def __init__(self, config_manager=None):
        """初始化Worker客户端"""
        self.config = config_manager or get_config()
        self.logger = logging.getLogger(__name__)

        # 检查Worker是否启用
        if not self.config.is_worker_enabled():
            raise ValueError("Worker功能未启用，请在配置中启用Worker")

        # 初始化组件
        self.scheduler_connector = None
        self.task_dispatcher = None
        self.oss_uploader = None

        # 状态管理
        self.is_running = False
        self.is_stopping = False
        self.start_time = None

        # 统计信息
        self.stats = {
            "tasks_received": 0,
            "tasks_completed": 0,
            "tasks_failed": 0,
            "start_time": None,
            "last_task_time": None
        }

        # 初始化组件
        self._initialize_components()

        # 注册信号处理器
        self._setup_signal_handlers()

        self.logger.info("Worker客户端初始化完成")

    def _initialize_components(self):
        """初始化各个组件"""
        try:
            # 初始化调度系统连接器
            self.scheduler_connector = SchedulerConnector(self.config)
            self.scheduler_connector.set_task_received_callback(self._handle_remote_task)

            # 初始化任务分发器
            self.task_dispatcher = TaskDispatcher()

            # 设置任务分发器的回调
            self.task_dispatcher.set_progress_callback(self._handle_task_progress)
            self.task_dispatcher.set_completion_callback(self._handle_task_completion)

            # 初始化OSS上传器（如果配置了）
            oss_config = self.config.get_oss_config()
            if oss_config.get('enabled', False):
                self.oss_uploader = OSSUploader(oss_config)
                self.logger.info("OSS上传器已初始化")

            self.logger.info("所有组件初始化完成")

        except Exception as e:
            self.logger.error(f"组件初始化失败: {e}")
            raise

    def _setup_signal_handlers(self):
        """设置信号处理器"""
        try:
            import threading
            # 检查是否在主线程中
            if threading.current_thread() is threading.main_thread():
                signal.signal(signal.SIGINT, self._signal_handler)
                signal.signal(signal.SIGTERM, self._signal_handler)
                self.logger.debug("信号处理器设置完成")
            else:
                self.logger.debug("非主线程，跳过信号处理器设置")
        except AttributeError:
            # Windows可能不支持某些信号
            self.logger.debug("部分信号处理器设置失败（正常情况）")
        except Exception as e:
            self.logger.debug(f"信号处理器设置异常: {e}")

    def _signal_handler(self, signum, frame):
        """信号处理器"""
        self.logger.info(f"收到信号 {signum}，开始优雅关闭...")
        self.stop()

    def start(self) -> bool:
        """启动Worker客户端"""
        try:
            if self.is_running:
                self.logger.warning("Worker已在运行中")
                return True

            self.logger.info("正在启动Worker客户端...")

            # 注册到调度系统
            if not self.scheduler_connector.register_worker():
                self.logger.error("Worker注册失败")
                return False

            # 启动心跳和任务轮询
            self.scheduler_connector.start_heartbeat()
            self.scheduler_connector.start_task_polling()

            # 更新状态
            self.is_running = True
            self.is_stopping = False
            self.start_time = datetime.now()
            self.stats["start_time"] = self.start_time.isoformat()

            # 启动状态监控线程
            self._start_monitoring()

            self.logger.info("Worker客户端启动成功")
            return True

        except Exception as e:
            self.logger.error(f"Worker启动失败: {e}")
            return False

    def stop(self):
        """停止Worker客户端"""
        if not self.is_running or self.is_stopping:
            return

        self.logger.info("正在停止Worker客户端...")
        self.is_stopping = True

        try:
            # 停止调度系统连接器
            if self.scheduler_connector:
                self.scheduler_connector.stop()

            # 等待当前任务完成（可选，这里简化处理）
            self._wait_for_current_tasks()

            # 更新状态
            self.is_running = False

            self.logger.info("Worker客户端已停止")

        except Exception as e:
            self.logger.error(f"停止Worker异常: {e}")
        finally:
            self.is_stopping = False

    def _start_monitoring(self):
        """启动状态监控线程"""
        def monitor_loop():
            """监控循环"""
            last_log_time = time.time()
            log_interval = 300  # 每5分钟记录一次状态

            while self.is_running and not self.is_stopping:
                try:
                    current_time = time.time()

                    # 定期记录状态
                    if current_time - last_log_time >= log_interval:
                        self._log_status()
                        last_log_time = current_time

                    time.sleep(30)  # 每30秒检查一次

                except Exception as e:
                    self.logger.error(f"监控循环异常: {e}")
                    time.sleep(60)

        monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
        monitor_thread.start()
        self.logger.debug("状态监控线程已启动")

    def _handle_remote_task(self, remote_task: RemoteTask):
        """处理远程任务"""
        try:
            self.logger.info(f"收到远程任务: {remote_task.id}, 类型: {remote_task.taskType}")

            # 更新统计
            self.stats["tasks_received"] += 1
            self.stats["last_task_time"] = datetime.now().isoformat()

            # 分发任务到任务处理器
            result = self.task_dispatcher.dispatch_remote_task(remote_task)

            if result.get("success"):
                self.logger.info(f"远程任务分发成功: {remote_task.id}")

                # 【关键修复】立即调用startTask接口,将任务状态从CLAIMED改为PROCESSING
                # 这样可以确保任务状态与实际执行状态同步
                try:
                    start_success = self.scheduler_connector.report_task_start(remote_task.id)
                    if start_success:
                        self.logger.info(f"任务开始执行已报告: {remote_task.id}")
                    else:
                        self.logger.warning(f"任务开始执行报告失败: {remote_task.id}")
                except Exception as start_e:
                    self.logger.error(f"报告任务开始异常: {remote_task.id}, {start_e}")
            else:
                error_msg = result.get("message", "任务分发失败")
                self.logger.error(f"远程任务分发失败: {remote_task.id}, {error_msg}")

                # 向调度系统报告失败
                self.scheduler_connector.report_task_failed(remote_task.id, error_msg)
                self.stats["tasks_failed"] += 1

        except Exception as e:
            error_msg = f"处理远程任务异常: {str(e)}"
            self.logger.error(error_msg)

            # 向调度系统报告失败
            try:
                self.scheduler_connector.report_task_failed(remote_task.id, error_msg)
            except Exception as report_e:
                self.logger.error(f"报告任务失败异常: {report_e}")

            self.stats["tasks_failed"] += 1

    def _handle_task_progress(self, task_id: str, progress: int):
        """处理任务进度更新"""
        try:
            self.logger.debug(f"任务进度更新: {task_id}, 进度: {progress}%")

            # 向调度系统报告进度
            # 注意:任务开始(startTask)已经在_handle_remote_task中调用过了
            # 这里只需要报告进度更新即可
            self.scheduler_connector.report_task_progress(task_id, progress)

        except Exception as e:
            self.logger.warning(f"处理任务进度异常: {task_id}, {e}")

    def _handle_task_completion(self, task_id: str, completion_data: Optional[Dict[str, Any]],
                              oss_video_url: Optional[str] = None, error_message: Optional[str] = None):
        """处理任务完成"""
        try:
            if error_message:
                # 任务失败
                self.logger.error(f"任务执行失败: {task_id}, 错误: {error_message}")
                self.scheduler_connector.report_task_failed(task_id, error_message)
                self.stats["tasks_failed"] += 1
            else:
                # 任务成功
                self.logger.info(f"任务执行成功: {task_id}")

                # 准备结果数据
                result_data = completion_data or {}

                # 如果启用了OSS且没有OSS URL，尝试上传
                if self.oss_uploader and not oss_video_url:
                    final_path = result_data.get("final_path")
                    if final_path:
                        oss_video_url = self._upload_to_oss(final_path, task_id)

                # 获取视频信息（如果有）
                enhanced_result = {}
                if result_data.get("final_path"):
                    video_info = self._get_video_info(result_data["final_path"])
                    enhanced_result.update(video_info)

                # 向调度系统报告完成
                self.scheduler_connector.report_task_completed(task_id, enhanced_result, oss_video_url)
                self.stats["tasks_completed"] += 1

        except Exception as e:
            error_msg = f"处理任务完成异常: {str(e)}"
            self.logger.error(error_msg)

            # 向调度系统报告失败
            try:
                self.scheduler_connector.report_task_failed(task_id, error_msg)
            except Exception as report_e:
                self.logger.error(f"报告任务失败异常: {report_e}")

            self.stats["tasks_failed"] += 1

    def _get_video_info(self, file_path: str) -> Dict[str, Any]:
        """获取视频文件信息"""
        try:
            import os

            if not os.path.exists(file_path):
                return {}

            # 获取文件大小
            file_size = os.path.getsize(file_path)

            # 尝试获取视频时长
            video_duration = 0
            try:
                # 可以使用ffprobe或其他工具获取视频时长
                # 这里先简化处理，可以后续扩展
                pass
            except:
                pass

            return {
                "fileSize": file_size,
                "videoDuration": video_duration
            }

        except Exception as e:
            self.logger.warning(f"获取视频信息失败: {e}")
            return {}

    def _upload_to_oss(self, file_path: str, task_id: str) -> Optional[str]:
        """上传文件到OSS"""
        try:
            if not self.oss_uploader:
                return None

            self.logger.info(f"开始上传文件到OSS: {file_path}")

            # 生成OSS文件名
            import os
            file_ext = os.path.splitext(file_path)[1]
            oss_key = f"{task_id}{file_ext}"

            # 上传文件
            upload_result = self.oss_uploader.upload_file(
                local_path=file_path,
                oss_key=oss_key,
                folder="videos"
            )

            if upload_result["success"]:
                oss_url = upload_result["oss_url"]
                self.logger.info(f"OSS上传成功: {oss_url}")
                return oss_url
            else:
                self.logger.error(f"OSS上传失败: {upload_result['message']}")
                return None

        except Exception as e:
            self.logger.error(f"OSS上传异常: {e}")
            return None

    def _wait_for_current_tasks(self, timeout: int = 30):
        """等待当前任务完成"""
        self.logger.info("等待当前任务完成...")

        start_time = time.time()
        while time.time() - start_time < timeout:
            # 检查是否还有正在执行的任务
            if self.scheduler_connector.current_task_count == 0:
                self.logger.info("所有任务已完成")
                return

            time.sleep(1)

        self.logger.warning(f"等待任务完成超时（{timeout}秒）")

    def _log_status(self):
        """记录状态信息"""
        try:
            # 获取组件状态
            connector_status = self.scheduler_connector.get_status()

            # 计算运行时间
            uptime = "未知"
            if self.start_time:
                uptime_seconds = (datetime.now() - self.start_time).total_seconds()
                if uptime_seconds < 3600:
                    uptime = f"{int(uptime_seconds // 60)}分钟"
                else:
                    hours = int(uptime_seconds // 3600)
                    minutes = int((uptime_seconds % 3600) // 60)
                    uptime = f"{hours}小时{minutes}分钟"

            status_info = {
                "worker_id": connector_status.get("worker_id"),
                "uptime": uptime,
                "is_registered": connector_status.get("is_registered"),
                "current_tasks": connector_status.get("current_task_count"),
                "max_tasks": connector_status.get("max_concurrent_tasks"),
                "stats": self.stats
            }

            self.logger.info(f"Worker状态: {status_info}")

        except Exception as e:
            self.logger.error(f"记录状态异常: {e}")

    def get_status(self) -> Dict[str, Any]:
        """获取Worker状态"""
        try:
            connector_status = self.scheduler_connector.get_status() if self.scheduler_connector else {}

            # 计算运行时间
            uptime_seconds = 0
            if self.start_time:
                uptime_seconds = (datetime.now() - self.start_time).total_seconds()

            return {
                "is_running": self.is_running,
                "is_stopping": self.is_stopping,
                "start_time": self.stats.get("start_time"),
                "uptime_seconds": uptime_seconds,
                "connector_status": connector_status,
                "stats": self.stats,
                "timestamp": datetime.now().isoformat()
            }

        except Exception as e:
            self.logger.error(f"获取状态异常: {e}")
            return {
                "is_running": self.is_running,
                "error": str(e),
                "timestamp": datetime.now().isoformat()
            }

    def run_forever(self):
        """持续运行Worker（阻塞方法）"""
        if not self.start():
            return False

        try:
            self.logger.info("Worker正在运行，按Ctrl+C停止...")

            while self.is_running:
                time.sleep(1)

        except KeyboardInterrupt:
            self.logger.info("收到键盘中断信号")
        except Exception as e:
            self.logger.error(f"运行异常: {e}")
        finally:
            self.stop()

        return True


def main():
    """主函数"""
    # 配置日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )

    logger = logging.getLogger(__name__)

    try:
        # 创建Worker客户端
        worker = WorkerClient()

        # 显示启动信息
        config = get_config()
        worker_config = config.get_worker_config()

        print("=" * 60)
        print("剪映草稿自动化 Worker 客户端")
        print("=" * 60)
        print(f"Worker ID: {worker_config.get('id', 'unknown')}")
        print(f"Worker名称: {worker_config.get('workerName', 'unknown')}")
        print(f"调度系统: {worker_config.get('api_base', 'unknown')}")
        print(f"最大并发任务: {worker_config.get('maxConcurrentTasks', 4)}")
        print(f"支持能力: {', '.join(worker_config.get('capabilities', []))}")
        print("=" * 60)

        # 运行Worker
        success = worker.run_forever()

        if success:
            logger.info("Worker正常退出")
        else:
            logger.error("Worker启动失败")
            return 1

    except Exception as e:
        logger.error(f"Worker运行异常: {e}")
        return 1

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())